// #pragma once
#ifndef __BLOCK_QUEUE__
#define __BLOCK_QUEUE__

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <queue>

#define DefaultMaxima 5

template<class T>
class BlockQueue
{
public:
    BlockQueue(int maxima = DefaultMaxima): _maxima(maxima)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);

        low = maxima / 3;
        high = (maxima * 2) / 3;
    }
    T pop()
    {
        pthread_mutex_lock(&_lock);
        //当内存数据结构中没有数据时，就去消费者条件变量中等待
        if(_q.size() == 0)
        {
            pthread_cond_wait(&_c_cond, &_lock);
        }

        T front = _q.front();
        _q.pop();
        // std::cout << "a + b = ?" << std::endl;
        if(high > _q.size()) pthread_cond_signal(&_c_cond);
        //执行以上语句，一定会消费到生产资源，这时我们就唤醒生产者
        pthread_cond_signal(&_p_cond);

        pthread_mutex_unlock(&_lock);

        return front;
    }

    void push(const T& data)
    {
        pthread_mutex_lock(&_lock);
        //生产者生产到一定数量，就去生产者条件变量中等待
        if(_q.size() == _maxima)
        {
            pthread_cond_wait(&_p_cond, &_lock);
            // sleep(1);
        }
        _q.push(data);
        // std::cout << "生产了一个资源" << data << std::endl;
        if(low < _q.size()) pthread_cond_signal(&_p_cond);
        //当生产者执行完以上生产语句之后，特定的内存结构中一定有数据
        //这时我们就唤醒消费者
        pthread_cond_signal(&_c_cond);

        pthread_mutex_unlock(&_lock);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
private:
    std::queue<T> _q;  //队列

    // uint64_t minima;
    int _maxima; //生产者最大生产个数

    pthread_mutex_t _lock;
    pthread_cond_t _c_cond; 
    pthread_cond_t _p_cond; 

    //优化
    int low;
    int high;
};


#endif